///////////////////////////////////////////////////////////////////////////////
// File:        TcpConnection.cc
// Author:      671643387@qq.com
// Description:
///////////////////////////////////////////////////////////////////////////////

#include <cassert>
#include "common/Logger.hpp"
#include "common/TcpServer.hpp"
#include "common/TcpConnection.hpp"
using namespace monkey::common;

#if defined(__WINDOWS__)
#pragma warning(disable:4355)
#endif

///////////////////////////////////////////////////////////////////////////////

TcpConnection::TcpConnection()
    : conn_(NULL)
    , serv_(NULL)
    , is_(*this)
{

}

TcpConnection::~TcpConnection(void)
{

}

///////////////////////////////////////////////////////////////////////////////

int TcpConnection::GetID(void)
{
    assert(conn_);
    return pio_connection_get_id(conn_);
}

void TcpConnection::Close(void)
{
    assert(conn_);
    pio_connection_close(conn_);
}

bool TcpConnection::ReadImmediately(void)
{
#if defined(__DEBUG__)
    MKLOG_LOG("%d, TcpConnection::ReadImmediately\n", GetID());
#endif
    return is_.Fill() != SOCKET_ERROR;
}

bool TcpConnection::NotifyWrite(void)
{
    assert(!write_pending_);
    if (0 == pio_connection_notify_write(conn_))
    {
        write_pending_ = true;
        return true;
    }
    return false;
}

unsigned int TcpConnection::Read(char* buf, unsigned int length)
{
    return is_.Read(buf, length);
}

unsigned int TcpConnection::Peek(char* buf, unsigned int length)
{
    return is_.Peek(buf, length);
}

unsigned int TcpConnection::Skip(unsigned int length)
{
    return is_.Skip(length);
}

int TcpConnection::Write(const char* buf, unsigned int length)
{
    return pio_connection_write(conn_, buf, (int)length, 0);
}

bool TcpConnection::WritePending(void) const
{
    return write_pending_;
}

///////////////////////////////////////////////////////////////////////////////

bool TcpConnection::OnRead(void)
{
#if defined(__DEBUG__)
    MKLOG_LOG("%d, TcpConnection::OnRead\n", GetID());
#endif
    return is_.Fill() != SOCKET_ERROR;
}

bool TcpConnection::OnWrite(void)
{
    assert(write_pending_);
#if defined(__DEBUG__)
    MKLOG_LOG("%d, TcpConnection::OnWrite\n", GetID());
#endif
    write_pending_ = false;
    return true;
}

void TcpConnection::OnClose(void)
{
    assert(serv_);
#if defined(__DEBUG__)
    MKLOG_LOG("%d, TcpConnection::OnClose\n", GetID());
#endif
    serv_->FreeConnection(this);
}

///////////////////////////////////////////////////////////////////////////////

void TcpConnection::_OnRead(struct pio_connection* conn, void* arg)
{
    assert(conn && arg);
    TcpConnection* pConn = static_cast<TcpConnection*>(arg);
    if (!pConn->OnRead()) pConn->Close();
}

void TcpConnection::_OnWrite(struct pio_connection* conn, void* arg)
{
    assert(conn && arg);
    TcpConnection* pConn = static_cast<TcpConnection*>(arg);
    if (!pConn->OnWrite()) pConn->Close();
}

void TcpConnection::_OnClose(struct pio_connection* conn, void* arg)
{
    assert(conn && arg);
    TcpConnection* pConn = static_cast<TcpConnection*>(arg);
    pConn->OnClose();
    pio_connection_set_userdata(conn, NULL);
}

///////////////////////////////////////////////////////////////////////////////

void TcpConnection::_InitConnection(struct pio_connection* conn, TcpServer* serv)
{
    assert(conn && serv);
    conn_ = conn;
    serv_ = serv;
}